package  ntlmssp 
 
import  ( 
	"bytes"  
	"encoding/base64"  
	"io"  
	"io/ioutil"  
	"net/http"  
	"strings"  
) 
 
 
 
func  GetDomain  (user  string ) (string , string , bool ) { 
	domain  := ""  
	domainNeeded  := false  
 
	if  strings .Contains (user , "\\" ) { 
		ucomponents  := strings .SplitN (user , "\\" , 2 ) 
		domain  = ucomponents [0 ] 
		user  = ucomponents [1 ] 
		domainNeeded  = true  
	} else  if  strings .Contains (user , "@" ) { 
		domainNeeded  = false  
	} else  { 
		domainNeeded  = true  
	} 
	return  user , domain , domainNeeded  
} 
 
 
 
type  Negotiator  struct { http .RoundTripper  } 
 
 
 
func  (l  Negotiator ) RoundTrip (req  *http .Request ) (res  *http .Response , err  error ) { 
	 
	rt  := l .RoundTripper  
	if  rt  == nil  { 
		rt  = http .DefaultTransport  
	} 
	 
	reqauth  := authheader (req .Header .Values ("Authorization" )) 
	if  !reqauth .IsBasic () { 
		return  rt .RoundTrip (req ) 
	} 
	reqauthBasic  := reqauth .Basic () 
	 
	body  := bytes .Buffer {} 
	if  req .Body  != nil  { 
		_, err  = body .ReadFrom (req .Body ) 
		if  err  != nil  { 
			return  nil , err  
		} 
 
		req .Body .Close () 
		req .Body  = ioutil .NopCloser (bytes .NewReader (body .Bytes ())) 
	} 
	 
 
	req .Header .Del ("Authorization" ) 
	res , err  = rt .RoundTrip (req ) 
	if  err  != nil  { 
		return  nil , err  
	} 
	if  res .StatusCode  != http .StatusUnauthorized  { 
		return  res , err  
	} 
	resauth  := authheader (res .Header .Values ("Www-Authenticate" )) 
	if  !resauth .IsNegotiate () && !resauth .IsNTLM () { 
		 
		req .Header .Set ("Authorization" , string (reqauthBasic )) 
		io .Copy (ioutil .Discard , res .Body ) 
		res .Body .Close () 
		req .Body  = ioutil .NopCloser (bytes .NewReader (body .Bytes ())) 
 
		res , err  = rt .RoundTrip (req ) 
		if  err  != nil  { 
			return  nil , err  
		} 
		if  res .StatusCode  != http .StatusUnauthorized  { 
			return  res , err  
		} 
		resauth  = authheader (res .Header .Values ("Www-Authenticate" )) 
	} 
 
	if  resauth .IsNegotiate () || resauth .IsNTLM () { 
		 
		io .Copy (ioutil .Discard , res .Body ) 
		res .Body .Close () 
 
		 
		u , p , err  := reqauth .GetBasicCreds () 
		if  err  != nil  { 
			return  nil , err  
		} 
 
		 
		domain  := ""  
		u , domain , domainNeeded  := GetDomain (u ) 
 
		 
		negotiateMessage , err  := NewNegotiateMessage (domain , "" ) 
		if  err  != nil  { 
			return  nil , err  
		} 
		if  resauth .IsNTLM () { 
			req .Header .Set ("Authorization" , "NTLM " +base64 .StdEncoding .EncodeToString (negotiateMessage )) 
		} else  { 
			req .Header .Set ("Authorization" , "Negotiate " +base64 .StdEncoding .EncodeToString (negotiateMessage )) 
		} 
 
		req .Body  = ioutil .NopCloser (bytes .NewReader (body .Bytes ())) 
 
		res , err  = rt .RoundTrip (req ) 
		if  err  != nil  { 
			return  nil , err  
		} 
 
		 
		resauth  = authheader (res .Header .Values ("Www-Authenticate" )) 
		challengeMessage , err  := resauth .GetData () 
		if  err  != nil  { 
			return  nil , err  
		} 
		if  !(resauth .IsNegotiate () || resauth .IsNTLM ()) || len (challengeMessage ) == 0  { 
			 
			return  res , nil  
		} 
		io .Copy (ioutil .Discard , res .Body ) 
		res .Body .Close () 
 
		 
		authenticateMessage , err  := ProcessChallenge (challengeMessage , u , p , domainNeeded ) 
		if  err  != nil  { 
			return  nil , err  
		} 
		if  resauth .IsNTLM () { 
			req .Header .Set ("Authorization" , "NTLM " +base64 .StdEncoding .EncodeToString (authenticateMessage )) 
		} else  { 
			req .Header .Set ("Authorization" , "Negotiate " +base64 .StdEncoding .EncodeToString (authenticateMessage )) 
		} 
 
		req .Body  = ioutil .NopCloser (bytes .NewReader (body .Bytes ())) 
 
		return  rt .RoundTrip (req ) 
	} 
 
	return  res , err  
} 
  
The pages are generated with Golds   v0.6.7 . (GOOS=linux GOARCH=amd64)
Golds  is a Go 101  project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @Go100and1  (reachable from the left QR code) to get the latest news of Golds .